package com.info33.platform.common.pay;

import com.alibaba.fastjson.JSON;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.util.ResponseChecker;
import com.alipay.easysdk.payment.app.models.AlipayTradeAppPayResponse;
import com.alipay.easysdk.payment.common.models.*;
import com.info33.platform.common.mvc.vo.Result;
import com.info33.platform.config.pay.AliPayConfig;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author debj
 * @version 1.0
 * @date 2021/3/30 8:35
 */
@Slf4j
public class AlipayUtil {

    /**
     * 支付成功对象
     */
    private static final List<String> STATUS_LIST = new ArrayList<>();

    private AlipayUtil() {
        STATUS_LIST.add("TRADE_SUCCESS");
        STATUS_LIST.add("TRADE_FINISHED");
    }

    public static AlipayNotifyParam formatRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        Map<String, String> fotMap = new HashMap<>(16);
        Map<String, String[]> requestMap = request.getParameterMap();
        for (String name : requestMap.keySet()) {
            String[] values = requestMap.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            // 乱码解决，这段代码在出现乱码时使用
            // valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            fotMap.put(name, valueStr);
        }
        log.info("支付宝回调，{}", fotMap.toString());
        // 验证，回调：调用 SDK 验证签名
        if (Boolean.FALSE.equals(Factory.Payment.Common().verifyNotify(fotMap))) {
            response.getWriter().write("failure");
            throw new AlipayException("SDK 验证签名失败");
        }
        return JSON.parseObject(JSON.toJSONString(fotMap), AlipayNotifyParam.class);
    }

    /**
     * 校验异常回调通知，是否有效
     * <p>需要在调用方法前，判断库中是否存在该订单号相关信息</p>
     *
     * @param paramEntity 阿里入参，映射实体对象
     * @param money       订单信息中金钱
     */
    public static void check(AlipayNotifyParam paramEntity, BigDecimal money) {
        if (money.compareTo(paramEntity.getTotalAmount()) != 0) {
            throw new AlipayException("金钱不一样");
        }
        // 校验通知中的seller_id（或者seller_email)是否为out_trade_no这笔单据的对应的操作方
        //（有的时候，一个商户可能有多个seller_id/seller_email），[注：第三步可根据实际情况省略]
        if (!paramEntity.getAppId().equals(AliPayConfig.getOptions().appId)) {
            throw new AlipayException("app_id 不一致");
        }
        if (STATUS_LIST.contains(paramEntity.getTradeStatus())) {
            log.error("支付宝交易状态：{},params:{}", paramEntity.getTradeStatus(), paramEntity.toString());
            throw new AlipayException("没有处理支付宝回调业务");
        }
    }

    /**
     * 默认订单有效期三十分钟
     *
     * @param asyncNotify 回调地址
     * @param subject     主题
     * @param orderNumber 订单编号
     * @param money       金钱
     * @return result
     * @throws Exception 异常
     */
    public static Result<Object> pay(String asyncNotify, String subject, String orderNumber, String money) throws Exception {
        AlipayTradeAppPayResponse response = Factory.Payment.App()
                .asyncNotify(asyncNotify)
                .optional("timeoutExpress", 30)
                .pay(subject, orderNumber, money);
        if (ResponseChecker.success(response)) {
            return Result.ok(null, response.getBody());
        }
        return Result.error("订单支付失败，请重试");
    }

    public static void cancel(String outTradeNo) throws Exception {
        AlipayTradeCancelResponse cancel = Factory.Payment.Common().cancel(outTradeNo);
        if (Boolean.FALSE.equals(ResponseChecker.success(cancel))) {
            log.error(cancel.msg);
            throw new AlipayException("订单取消失败");
        }
    }

    public static AlipayTradeRefundResponse refund(String outTradeNo, String money) throws Exception {
        AlipayTradeRefundResponse refund = Factory.Payment.Common().refund(outTradeNo, money);
        if (Boolean.FALSE.equals(ResponseChecker.success(refund))) {
            log.error(refund.msg);
//            throw new AlipayException("订单退款失败.可能是:"+refund.subMsg);
        }
        //refund.msg == 10000是支付成功
        return refund;
    }

    public static void close(String outTradeNo) throws Exception {
        AlipayTradeCloseResponse close = Factory.Payment.Common().close(outTradeNo);
        if (Boolean.FALSE.equals(ResponseChecker.success(close))) {
            log.error(close.msg);
            throw new AlipayException("订单关闭失败");
        }
    }

    public static AlipayTradeQueryResponse query(String outTradeNo) throws Exception {
        AlipayTradeQueryResponse query = Factory.Payment.Common().query(outTradeNo);
        if (Boolean.FALSE.equals(ResponseChecker.success(query))) {
            log.error(query.msg);
            throw new AlipayException("订单查询失败");
        }
        return query;
    }

    public static AlipayTradeFastpayRefundQueryResponse queryRefund(String outTradeNo, String outRequestNo) throws Exception {
        AlipayTradeFastpayRefundQueryResponse queryRefund = Factory.Payment.Common().queryRefund(outTradeNo, outRequestNo);
        if (Boolean.FALSE.equals(ResponseChecker.success(queryRefund))) {
            log.error(queryRefund.msg);
            throw new AlipayException("订单退款信息查询失败");
        }
        return queryRefund;
    }
}
